package com.miku.blog.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.miku.blog.domain.*;
import com.miku.blog.domain.pojo.LoginUser;
import com.miku.blog.domain.pojo.ResponseResult;
import com.miku.blog.domain.pojo.SystemConstance;
import com.miku.blog.domain.vo.PageVo;
import com.miku.blog.domain.vo.TalkVo;
import com.miku.blog.eume.HttpStatusEnum;
import com.miku.blog.exception.SystemException;
import com.miku.blog.service.*;
import com.miku.blog.mapper.TalkMapper;
import com.miku.blog.utils.BeanCopyUtils;
import com.miku.blog.utils.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author Miku
 * @description 针对表【tb_talk】的数据库操作Service实现
 * @createDate 2022-06-10 10:51:12
 */
@Service
public class TalkServiceImpl extends ServiceImpl<TalkMapper, Talk>
        implements TalkService {

    @Autowired
    private UserInfoService userInfoService;
    @Lazy
    @Autowired
    private CommentService commentService;
    @Autowired
    private TalkImagesService talkImagesService;
    @Autowired
    private LikeCountService likeCountService;

    @Override
    public ResponseResult getTalks(Integer current, Integer size,@Nullable Integer status) {
        LambdaQueryWrapper<Talk> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Objects.nonNull(status),Talk::getStatus, status)
                .orderByDesc(Talk::getIsTop)
                .orderByDesc(Talk::getCreateTime);
        Page<Talk> page = new Page<>(current, size);
        page(page, queryWrapper);
        List<Talk> talkList = page.getRecords();
        talkList.stream()
                .peek(talk -> {
                    UserInfo userInfo = userInfoService.getUserInfoByUserId(talk.getUserId());
                    talk.setAvatar(userInfo.getAvatar())
                            .setNickname(userInfo.getNickname());
                }).collect(Collectors.toList());
        List<TalkVo> talkVoList = BeanCopyUtils.copyListByType(talkList, TalkVo.class);
        talkVoList.stream()
                .peek(vo -> {
                    List<TalkImages> talkImageListBy = talkImagesService.getTalkImageListByTalkId(vo.getId());
                    List<String> imageList = talkImageListBy.stream()
                            .map(TalkImages::getImage)
                            .collect(Collectors.toList());

                    long talkLikeCount = likeCountService.getLikeCountByTargetIdAndType(vo.getId(),SystemConstance.LIKE_COUNT_TYPE_BY_TALK);
                    long commentCount = commentService.getCommentCountByArticleIdAndType(vo.getId(), SystemConstance.COMMENT_TYPE_BY_TALK_CODE);

                    vo.setCommentCount((int) commentCount)
                            .setImgList(imageList)
                            .setLikeCount((int) talkLikeCount);
                }).collect(Collectors.toList());
        PageVo<TalkVo> pageVo = new PageVo<>(page.getTotal(), talkVoList);
        return ResponseResult.ok().setData(pageVo);
    }


    @Override
    public ResponseResult getTalks(Integer current, Integer size) {

        ResponseResult responseResult;
        try {
            LoginUser loginUser = SecurityUtils.getLoginUser();
            if (SystemConstance.ROLE_ADMIN_ID.equals(loginUser.getRole().getId())){
                responseResult = getTalks(current,size,null);
            }else {
                responseResult = getTalks(current,size,SystemConstance.STATUS_PUBLIC);
            }
        } catch (Exception exception) {
            responseResult = getTalks(current,size,SystemConstance.STATUS_PUBLIC);
        }
        return responseResult;
    }

    @Override
    public ResponseResult getTalkDetailAdminById(Integer talkId) {
        TalkVo talkVo = getTalkDetailByIdAndStatus(talkId,null);
        return ResponseResult.ok().setData(talkVo);
    }


    @Override
    public ResponseResult getTalkDetailById(Integer talkId) {

        TalkVo talkVo;
        try {
            LoginUser loginUser = SecurityUtils.getLoginUser();
            if (SystemConstance.ROLE_ADMIN_ID.equals(loginUser.getRole().getId())){
                talkVo = getTalkDetailByIdAndStatus(talkId,null);
            }else {
                talkVo = getTalkDetailByIdAndStatus(talkId,SystemConstance.STATUS_PUBLIC);
            }
        } catch (Exception exception) {
            talkVo = getTalkDetailByIdAndStatus(talkId,SystemConstance.STATUS_PUBLIC);
        }
        return ResponseResult.ok().setData(talkVo);

    }

    private TalkVo getTalkDetailByIdAndStatus(Integer talkId,Integer status){
        LambdaQueryWrapper<Talk> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Talk::getId, talkId)
                .eq(Objects.nonNull(status),Talk::getStatus,status);
        Talk talk = getOne(queryWrapper);
        UserInfo userInfo = userInfoService.getUserInfoByUserId(talk.getUserId());
        talk.setAvatar(userInfo.getAvatar())
                .setNickname(userInfo.getNickname());
        TalkVo talkVo = BeanCopyUtils.copyObjectByType(talk, TalkVo.class);
        List<TalkImages> talkImagesList = talkImagesService.getTalkImageListByTalkId(talkVo.getId());
        List<String> images = talkImagesList.stream()
                .map(TalkImages::getImage)
                .collect(Collectors.toList());

        long likeCount = likeCountService.getLikeCountByTargetIdAndType(talkId,SystemConstance.LIKE_COUNT_TYPE_BY_TALK);
        long commentCount = commentService.getCommentCountByArticleIdAndType(talkId, SystemConstance.COMMENT_TYPE_BY_TALK_CODE);
        talkVo.setImgList(images)
                .setLikeCount((int) likeCount)
                .setCommentCount((int) commentCount);
        return talkVo;
    }

    @Transactional
    @Override
    public ResponseResult addTalk(TalkVo talkVo) {
        String content = talkVo.getContent();
        Integer isTop = talkVo.getIsTop();
        Integer status = talkVo.getStatus();
        if (Objects.isNull(isTop) || Objects.isNull(status) || !StringUtils.hasText(content)
                || (!SystemConstance.IS_TOP.equals(isTop) && !SystemConstance.NOT_TOP.equals(isTop))
                || (!SystemConstance.STATUS_PUBLIC.equals(status) && !SystemConstance.STATUS_PRIVATE.equals(status))
        ) {
            return new ResponseResult(HttpStatusEnum.PARAM_ERROR);
        }

        Talk talk = BeanCopyUtils.copyObjectByType(talkVo, Talk.class);
        Integer id = talk.getId();
        if (Objects.isNull(id)) {
            talk.setUserId(SecurityUtils.getUserAuth().getId());
            if (save(talk)) {
                List<String> imgList = talkVo.getImgList();
                if (Objects.nonNull(imgList) && imgList.size() > 0) {
                    imgList.stream()
                            .peek(img -> {
                                TalkImages talkImages = new TalkImages();
                                talkImages.setImage(img)
                                        .setTalkId(talk.getId());
                                if (!talkImagesService.save(talkImages)) {
                                    throw new SystemException(HttpStatusEnum.INSERT_DATA_ERROR);
                                }
                            }).collect(Collectors.toList());
                }
            } else {
                return new ResponseResult(HttpStatusEnum.INSERT_DATA_ERROR);
            }
        } else {
            LambdaUpdateWrapper<Talk> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(Talk::getId,id)
                    .set(Talk::getContent,content)
                    .set(Talk::getStatus,status)
                    .set(Talk::getIsTop,isTop)
                    .set(Talk::getUpdateTime,new Date());
            if (update(updateWrapper)) {
                List<String> imgList = talkVo.getImgList();
                if (Objects.nonNull(imgList) && imgList.size() > 0) {
                    List<TalkImages> talkImagesList = talkImagesService.getTalkImageListByTalkId(talk.getId());
                    if (Objects.nonNull(talkImagesList) && talkImagesList.size() == imgList.size()) {
                        List<String> list = talkImagesList.stream()
                                .map(TalkImages::getImage)
                                .collect(Collectors.toList());
                        if (list.containsAll(imgList)) {
                            return ResponseResult.ok();
                        }
                    }
                    talkImagesService.delTalkImageByTalkId(talk.getId());
                    imgList.stream()
                            .peek(img -> {
                                TalkImages talkImages = new TalkImages();
                                talkImages.setImage(img)
                                        .setTalkId(talk.getId());
                                if (!talkImagesService.save(talkImages)) {
                                    throw new SystemException(HttpStatusEnum.INSERT_DATA_ERROR);
                                }
                            }).collect(Collectors.toList());
                } else {
                    talkImagesService.delTalkImageByTalkId(talk.getId());
                }
            } else {
                return new ResponseResult(HttpStatusEnum.UPDATE_DATA_ERROR);
            }
        }
        return ResponseResult.ok();
    }


    @Override
    public ResponseResult getTalkContents() {

        LambdaQueryWrapper<Talk> queryWrapper = new LambdaQueryWrapper<>();

        checkAdmin(queryWrapper);

        queryWrapper.orderByDesc(Talk::getCreateTime);
//                .eq(Talk::getStatus,SystemConstance.STATUS_PUBLIC);

        List<Talk> talkList = list(queryWrapper);

        List<String> contents = talkList.stream()
                .map(Talk::getContent)
                .collect(Collectors.toList());

        return ResponseResult.ok().setData(contents);
    }


    @Transactional
    @Override
    public ResponseResult delTalks(Integer[] talkIds) {

        for (Integer talkId : talkIds) {

            List<Comment> commentList
                    = commentService.getArticleAllCommentListByIdAndType(talkId, SystemConstance.COMMENT_TYPE_BY_TALK_CODE);
            commentList.stream()
                    .peek(comment -> {
                        likeCountService.delLikeCountByTargetIdAndType(comment.getId(), SystemConstance.LIKE_COUNT_TYPE_BY_COMMENT);
                    }).collect(Collectors.toList());

            likeCountService.delLikeCountByTargetIdAndType(talkId, SystemConstance.LIKE_COUNT_TYPE_BY_TALK);
            commentService.deleteCommentByArticleIdAndType(talkId, SystemConstance.COMMENT_TYPE_BY_TALK_CODE);

            if (!removeById(talkId)) {
                throw new SystemException(HttpStatusEnum.REMOVE_DATA_ERROR);
            }

        }

        return ResponseResult.ok();
    }




    private void checkAdmin(LambdaQueryWrapper<Talk> queryWrapper){
        try {
            LoginUser loginUser = SecurityUtils.getLoginUser();
            if (!SystemConstance.ROLE_ADMIN_ID.equals(loginUser.getRole().getId())) {
                queryWrapper.eq(Talk::getStatus, SystemConstance.STATUS_PUBLIC);
            }
        } catch (Exception exception) {
            queryWrapper.eq(Talk::getStatus, SystemConstance.STATUS_PUBLIC);
        }
    }


}




